package com.tre.jdevtemplateboot.common.util;

import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.*;
import java.util.stream.Collectors;

public class JDevBase64Utils {

    private static final int OFF_SET = 3;
    private static final String SEPARATOR_LETTER = "_";
    private static final String JOIN_LETTER = ",";
    private static final Random rand = new SecureRandom();

    private JDevBase64Utils() {
    }

    /**
     * Base64转码
     *
     * @param context
     * @return
     */
    public static String encoder(String context) {
        //① 随机打乱要加密的字符顺序  如并记入 打乱的序号如
        if (!StringUtils.hasLength(context)) {
            return "";
        }
        LetterIdx mapOrigin = null;
        List<LetterIdx> originList = new ArrayList<>();
        char[] arr = context.toCharArray();
        if (arr.length > 0) {
            for (int i = 0, size = arr.length; i < size; i++) {
                mapOrigin = new LetterIdx();
                mapOrigin.setLetter(arr[i]);
                mapOrigin.setIdx(i);
                originList.add(mapOrigin);
            }
        }

        Collections.shuffle(originList, rand);
        StringBuilder disorderLetter = new StringBuilder();
        String disorderIdx = "";
        List<String> idxList = new ArrayList<>();
        for (LetterIdx map : originList) {
            disorderLetter.append(map.getLetter());
            idxList.add(map.getIdx().toString());
        }
        disorderIdx = String.join(JOIN_LETTER, idxList);

        //② 标准base64 加密打乱的序号字符串
        String base64DisorderIdx = Base64.getEncoder()
                .encodeToString(disorderIdx.getBytes(StandardCharsets.UTF_8));

        //③ 打乱的字符 +'_'+ 加密后的乱序字符串
        String disOrderLetterAndIdx = disorderLetter + SEPARATOR_LETTER + base64DisorderIdx;

        //④ 标准base64 加密以上
        String base64DisorderLetterAndIdx = Base64.getEncoder()
                .encodeToString(disOrderLetterAndIdx.getBytes(StandardCharsets.UTF_8));

        //⑤ 于第三个字符后插入随机字符
        StringBuilder base64Sb = new StringBuilder(base64DisorderLetterAndIdx);
        //随机取一个大写字母
        char capitalLetter = (char) (rand.nextInt(26) + 65);
        base64Sb.insert(OFF_SET, capitalLetter);
        return base64Sb.toString();
    }

    /**
     * Base64解码
     *
     * @param encoderContext
     * @return
     */
    public static String decoder(String encoderContext) {

        if (!StringUtils.hasLength(encoderContext)) {
            return "";
        }
        String originContext = "";
        StringBuilder sb = new StringBuilder(encoderContext);
        //① 移除第四个字符 ( 下标为 3 )
        String deleteCharContext = sb.deleteCharAt(OFF_SET).toString();

        //② 标准base64 解密
        byte[] base64decodedBytes = Base64.getDecoder().decode(deleteCharContext);
        String base64Decoder = new String(base64decodedBytes, StandardCharsets.UTF_8);
        String[] base64DecoderArray = base64Decoder.split(SEPARATOR_LETTER);

        if (base64DecoderArray.length > 1) {
            String disorderLetter = String.join(
                    SEPARATOR_LETTER, Arrays.copyOfRange(base64DecoderArray, 0, base64DecoderArray.length - 1));
            String base64DisorderIdx = base64DecoderArray[base64DecoderArray.length - 1];
            base64decodedBytes = Base64.getDecoder().decode(base64DisorderIdx);
            String base64IdxDecoder = new String(base64decodedBytes, StandardCharsets.UTF_8);
            char[] arr = disorderLetter.toCharArray();
            List<LetterIdx> originList = new ArrayList<>();
            LetterIdx mapOrigin = null;
            String[] disorderIdxArray = base64IdxDecoder.split(JOIN_LETTER);
            if (arr.length > 0) {
                for (int i = 0, size = arr.length; i < size; i++) {
                    mapOrigin = new LetterIdx();
                    mapOrigin.setLetter(arr[i]);
                    mapOrigin.setIdx(Integer.valueOf(disorderIdxArray[i]));
                    originList.add(mapOrigin);
                }
            }
            originContext = originList.stream()
                    .sorted(Comparator.comparingInt(LetterIdx::getIdx))
                    .map(LetterIdx::getLetter)
                    .map(String::valueOf)
                    .collect(Collectors.joining(""));
        }
        return originContext;
    }

    static class LetterIdx {
        private Object letter;
        private Integer idx;

        public Object getLetter() {
            return letter;
        }

        public void setLetter(Object letter) {
            this.letter = letter;
        }

        public Integer getIdx() {
            return idx;
        }

        public void setIdx(Integer idx) {
            this.idx = idx;
        }

        @Override
        public String toString() {
            return "LetterIdx{" +
                    "letter=" + letter +
                    ", idx=" + idx +
                    '}';
        }
    }

}
